package com.wms.oms.aspect;

import com.wms.oms.annotation.InventoryLock;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * @author zzm
 * @date 2022/12/21
 * @desc 库存锁注解
 */


@Aspect
@Component
@Slf4j
public class InventoryLockAspect {



    private static RedissonClient redissonClient;

    @Autowired
    public void setRedissonClient(RedissonClient redissonClient) {
        InventoryLockAspect.redissonClient = redissonClient;
    }


    @Around("@annotation(inventoryLock)")
    public void interceptOperation(ProceedingJoinPoint point, InventoryLock inventoryLock) {
        String skuId = inventoryLock.skuId();
        String warehouseId  = inventoryLock.warehouseId();

        Object[] args = point.getArgs();
        Method method = ((MethodSignature) point.getSignature()).getMethod();
        //获取被拦截方法参数名列表(使用Spring支持类库)
        LocalVariableTableParameterNameDiscoverer localVariableTable = new LocalVariableTableParameterNameDiscoverer();
        String[] paraNameArr = localVariableTable.getParameterNames(method);
        //使用SPEL进行key的解析
        ExpressionParser parser = new SpelExpressionParser();
        //SPEL上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
        //把方法参数放入SPEL上下文中
        for(int i=0;i<paraNameArr.length;i++) {
            context.setVariable(paraNameArr[i], args[i]);
        }
        String sid = null;
        // 使用变量方式传入业务动态数据
        if (skuId.matches("^#.*.$")) {
            sid = parser.parseExpression(skuId).getValue(context, String.class);
        }
        String wid = null;
        if (warehouseId.matches("^#.*.$")) {
            wid = parser.parseExpression(warehouseId).getValue(context, String.class);
        }
        System.out.println(sid);
        System.out.println(wid);

        RLock rlock = redissonClient.getLock("redisson:lock:inventory" + sid + "_" + wid);
        rlock.lock();
        try {
            point.proceed();
        }  catch (Throwable throwable) {
            throw new IllegalArgumentException(throwable.getMessage());
        }finally {
            rlock.unlock();
        }
    }

}
